import { usePrismTheme, useThemeConfig } from "@docusaurus/theme-common";
import {
  containsLineNumbers,
  parseCodeBlockTitle,
  parseLanguage,
  parseLines,
  useCodeWordWrap,
} from "@docusaurus/theme-common/internal";
import Line from "@theme/CodeBlock/Line";
import clsx from "clsx";
import Highlight, { defaultProps } from "prism-react-renderer";
import React from "react";
import { CommonCodeBlockContainer } from "./common-codeblock-container";
import { CommonCopyButton } from "./common-copy-button";
import { CommonWordWrapButton } from "./common-wordwrap-button";

const DefaultDocumentIcon = (props: React.SVGProps<SVGSVGElement>) => (
  <svg
    xmlns="http://www.w3.org/2000/svg"
    width={12}
    height={14}
    viewBox="0 0 12 14"
    fill="none"
    {...props}
  >
    <path
      fill="currentColor"
      fillRule="evenodd"
      d="M11 4.994V11.6A1.4 1.4 0 0 1 9.6 13H2.4A1.4 1.4 0 0 1 1 11.6V2.4A1.4 1.4 0 0 1 2.4 1h4.606a1.4 1.4 0 0 1 .99.41l2.594 2.594a1.4 1.4 0 0 1 .41.99ZM0 2.4A2.4 2.4 0 0 1 2.4 0h4.606a2.4 2.4 0 0 1 1.697.703l2.594 2.594A2.4 2.4 0 0 1 12 4.994V11.6A2.4 2.4 0 0 1 9.6 14H2.4A2.4 2.4 0 0 1 0 11.6V2.4ZM3.5 6a.5.5 0 0 0 0 1h5a.5.5 0 0 0 0-1h-5Zm0 2a.5.5 0 0 0 0 1h5a.5.5 0 0 0 0-1h-5Zm0 2a.5.5 0 0 0 0 1h3a.5.5 0 0 0 0-1h-3Z"
      clipRule="evenodd"
    />
  </svg>
);

const CodeBlockTitle = ({
  children,
  icon = <DefaultDocumentIcon />,
}: {
  children?: React.ReactNode;
  icon?: React.ReactNode;
}) => {
  return (
    <div
      className={clsx(
        "py-3",
        "px-4",
        "bg-gray-100 dark:bg-gray-700",
        "text-gray-800",
        "dark:text-gray-100",
        "text-xs",
        "flex items-center",
        "gap-2",
        "rounded-tl-lg",
        "rounded-tr-lg",
      )}
    >
      {icon}
      {children}
    </div>
  );
};

export const CodeBlockString = ({
  children,
  className: blockClassName = "",
  metastring,
  title: titleProp,
  showLineNumbers: showLineNumbersProp,
  language: languageProp,
  icon,
  style,
}) => {
  const {
    prism: { defaultLanguage, magicComments },
  } = useThemeConfig();
  const language =
    languageProp ?? parseLanguage(blockClassName) ?? defaultLanguage;
  const prismTheme = usePrismTheme();
  const wordWrap = useCodeWordWrap();
  // We still parse the metastring in case we want to support more syntax in the
  // future. Note that MDX doesn't strip quotes when parsing metastring:
  // "title=\"xyz\"" => title: "\"xyz\""
  const title = parseCodeBlockTitle(metastring) || titleProp;

  const { lineClassNames, code } = parseLines(children, {
    metastring,
    language,
    magicComments,
  });

  const showLineNumbers =
    showLineNumbersProp ?? containsLineNumbers(metastring);

  return (
    <CommonCodeBlockContainer
      as="div"
      className={clsx(
        "refine-common-code-block",
        language && `language-${language}`,
        "rounded-lg",
        "bg-refine-react-light-code",
        "dark:bg-refine-react-dark-code",
        "border",
        "border-gray-300",
        "dark:border-0",
        "mb-6",
        "relative",
        "refine-wider-container",
      )}
      style={style}
    >
      {title && <CodeBlockTitle icon={icon}>{title}</CodeBlockTitle>}
      <div className={clsx("relative", "pt-3", "pb-0", "not-prose")}>
        <Highlight
          {...defaultProps}
          theme={prismTheme}
          code={code}
          language={language ?? "text"}
        >
          {({ className, tokens, getLineProps, getTokenProps }) => (
            <pre
              tabIndex={0}
              ref={wordWrap.codeBlockRef}
              className={clsx(
                className,
                "bg-transparent",
                "!mt-0",
                "!mb-0",
                "m-0",
                "px-0",
                "pt-0",
                "font-jetBrains-mono",
                "pb-3",
              )}
            >
              <code
                className={clsx(
                  "font-[inherit]",
                  "bg-transparent",
                  "inline-block",
                  "min-w-full",
                )}
              >
                {tokens.map((line, i) => (
                  <Line
                    key={i}
                    line={line}
                    getLineProps={getLineProps}
                    getTokenProps={getTokenProps}
                    classNames={clsx(
                      lineClassNames[i],
                      "px-4",
                      "text-xs sm:text-sm 2xl:text-sm",
                    )}
                    showLineNumbers={showLineNumbers}
                  />
                ))}
              </code>
            </pre>
          )}
        </Highlight>
      </div>
      <div
        className={clsx(
          "absolute",
          title ? "top-2 right-2" : "top-3 right-3",
          "flex items-center gap-2",
        )}
      >
        {(wordWrap.isEnabled || wordWrap.isCodeScrollable) && (
          <CommonWordWrapButton
            onClick={wordWrap.toggle}
            isEnabled={wordWrap.isEnabled}
          />
        )}
        <CommonCopyButton className={clsx()} code={code} />
      </div>
    </CommonCodeBlockContainer>
  );
};
